﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using CheckersClientApplication.GameRoomServiceReference;
using CheckersClientApplication.Utility;
using System.Threading.Tasks;
using System.Threading;

namespace CheckersClientApplication
{
    /// <summary>
    /// Interaction logic for PlayRegionScreen.xaml
    /// </summary>
    public partial class PlayRegionScreen : Window
    {
        private int isOccupiedBy = 0;

        bool isFirsTime;
        Position GridStartPosition;
        Position GridEndPosition;

        //------------------------checkers Board UI----------------
        DateTime lastTimeUpdated;

        Image tempImg;
        StackPanel tempParentPanel;

        string strUriYellowKing;
        string strUriRedKing;
        //------------------------checkers Board UI----------------
        private int PlayerType = -1;

        private PlayerGameRoomViewModel objGameRoomPlayerViewModel;
        private GameRoomServiceReference.GameRoomServiceClient client_gm;
        public PlayRegionScreen()
        {
            MessageBox.Show("Play Screen without Player Object is not exceptable It may be due to corruption of the Application Please consider reinstalling or re-running");
            throw new Exception("Play Screen without Player Object is not exceptable It may be due to corruption of the Application Please consider reinstalling or re-running");
        }

   

        public PlayRegionScreen(PlayerGameRoomViewModel objGameRoom)
        {
            isFirsTime = true;
            //------------------------checkers Board UI----------------
            lastTimeUpdated = DateTime.Now;



            strUriRedKing = String.Format(@"pack://siteoforigin:,,,/Resources/RedKing.gif");
            strUriYellowKing = String.Format(@"pack://siteoforigin:,,,/Resources/YellowKing.gif");

            tempImg = null;
            tempParentPanel = null;

            GridStartPosition = new Position();
            GridEndPosition = new Position();


            //------------------------checkers Board UI----------------



            objGameRoomPlayerViewModel = objGameRoom;
            client_gm = new GameRoomServiceReference.GameRoomServiceClient();
            this.PlayerType = getPlayerType();


            InitializeComponent();


            //------------------------checkers Board UI----------------
            BindClickEventsOnPanel();
            //------------------------checkers Board UI----------------



            lblPlayerName.Content = "Welcome " + objGameRoomPlayerViewModel.player.PlayerName;
            
        }

        public void initMyUIElements() 
        {
            try{
                PoolingMovesFromServer();

                ////--------------for testing purpose--------
                //updateMovesPanel();
                //updateViewerPanel();
            }

            catch (Exception exp)
            {
                MessageBox.Show(exp.Message);
            }

        }

        private int getPlayerType()
        {

            var gameRoomclientList = client_gm.GetAllViewers(objGameRoomPlayerViewModel.gameRoom);

            var objPlayer = objGameRoomPlayerViewModel.player;

            

           foreach (clsGameRoomClient client in gameRoomclientList) 
           {
                if(client.Player.PlayerId == objPlayer.PlayerId)
                {
                    return client.PlayerType;
                }
           }

           return -1;
        }

        private void PoolingMovesFromServer() 
        {
            System.Windows.Threading.DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
            dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
            dispatcherTimer.Interval = new TimeSpan(0,0,1);
            dispatcherTimer.Start();


        }

        private void dispatcherTimer_Tick(object sender, EventArgs e)
        {
            updateMovesPanel();
            updateViewerPanel();
            UpdateReleaaseButton();
            checkWinEvent();
        }

        private void checkWinEvent()
        {

            try 
            {
                var gameWinner = client_gm.CheckForWinner(objGameRoomPlayerViewModel.gameRoom, objGameRoomPlayerViewModel.player);

                //MessageBox.Show("Game Win " + gameWinner + "--");

                if(gameWinner != null)
                {
                    statusLabel.Content = "Game Won by " + gameWinner.Player.PlayerName;
                    UnBindClickEventsOnPanel();
                }

            }
            catch(Exception exp)
            {
                MessageBox.Show(exp.Message);
            }


        }

        private void UnBindClickEventsOnPanel()
        {
            try
            {
                Grid grid = CheckersGrid;
                /*
                 *Bind the events on the panels in each grid 
                 * 
                 */
                //TODO: bind events to only the type of player


                foreach (UIElement element in grid.Children)
                {
                    StackPanel panel = (StackPanel)element;
                    
                    panel.MouseDown -= panel_click;
                }
            }

            catch (Exception exp)
            {
                MessageBox.Show(exp.Message);
            }
        }


        //------------------------checkers Board UI----------------
        private void BindClickEventsOnPanel()
        {
            try
            {
                Grid grid = CheckersGrid;
                /*
                 *Bind the events on the panels in each grid 
                 * 
                 */
                //TODO: bind events to only the type of player


                foreach (UIElement element in grid.Children)
                {
                    StackPanel panel = (StackPanel) element;
                    if (panel.Children.Count != 0)
                    {
                        foreach (var child in panel.Children)
                        {
                            if (child.GetType() == typeof (Image))
                            {
                                Image piece = (Image) child;
                                piece.Tag = false;
                            }
                        }
                    }
                    panel.MouseDown += panel_click;
                }
            }

            catch (Exception exp)
            {
                MessageBox.Show(exp.Message);
            }
        }


        private void panel_click(object sender, MouseButtonEventArgs e)
        {
            try{

                if (PlayerType == 2)
                {
                    statusLabel.Content = "View Only mode cannot play";
                    return;
                }

                if(isOccupiedBy != PlayerType)
                {
                    statusLabel.Content = "Plese Wait till other player releases the lock";
                    return;
                }


                
                if (e.Source.GetType() == typeof(StackPanel))
                {
                    StackPanel refPanel = (StackPanel)e.Source;

                    /*
                     * Check if the panel has childrens 
                     * */
                    if (tempImg != null)
                    {
                        if (refPanel.Children.Count == 0)
                        {
                            /*
                             * No children
                             * Therefore now move to check if the position is valid for the movement
                             * */
                            statusLabel.Content = "Piece Moved";


                            int clickedX2Location = Convert.ToInt32(Math.Floor(e.MouseDevice.GetPosition(CheckersGrid).X / 60.0));
                            int clickedY2Location = Convert.ToInt32(Math.Floor(e.MouseDevice.GetPosition(CheckersGrid).Y / 60.0));

                            Point imgPosition = tempImg.PointToScreen(new Point());
                            Point panelPosition = refPanel.PointToScreen(new Point());

                            GridStartPosition.XPos = Convert.ToInt32(Math.Floor(FirstStackPanel.PointToScreen(new Point()).X / 60));
                            GridStartPosition.YPos = Convert.ToInt32(Math.Floor(FirstStackPanel.PointToScreen(new Point()).Y / 60));

                            GridEndPosition.XPos = Convert.ToInt32(Math.Floor(LastStackPanel.PointToScreen(new Point()).X / 60));
                            GridEndPosition.YPos = Convert.ToInt32(Math.Floor(LastStackPanel.PointToScreen(new Point()).Y / 60));
                        

                            Position endPosition = new Position()
                            {
                                XPos = Convert.ToInt32(Math.Floor(panelPosition.X / 60)),
                                YPos = Convert.ToInt32(Math.Floor(panelPosition.Y / 60))
                            };

                            Position startPosition = new Position()
                            {
                                XPos = Convert.ToInt32(Math.Floor(imgPosition.X / 60)),
                                YPos = Convert.ToInt32(Math.Floor(imgPosition.Y / 60))
                            };


                            PieceMovementValidator validator = new PieceMovementValidator();
                            //---------------------------------check which type of player played the move i.e black or red-----------

                            string pieceName = tempImg.Name;
                            int pieceType = -1;

                            pieceType = whichTypePiece(pieceName);


                            //TODO check for king
                            if (validator.isValidMove(startPosition, endPosition, GridStartPosition, pieceType, (bool)tempImg.Tag, CheckersGrid.Children))
                            {

                                //------------------------validate if the endposition is not occupied by same type of piece or occupied by other type of piece

                                tempParentPanel.Children.Remove(tempImg);
                                tempImg.Opacity = 1.0;
                                refPanel.Children.Add(tempImg);

                                //MessageBox.Show("Sending to server");


                                bool isKing = false;

                            

                                //check if the piece has moved to the boundary of the grid
                                if (pieceType == 0) // yellow
                                {

                                    if (endPosition.YPos == GridEndPosition.YPos)
                                    {
                                        //TODO: over here change the image source to king and also update the piece ID 
                                        isKing = true;
                                        if (pieceType == 0)
                                        {
                                            tempImg.Source = new BitmapImage(new Uri(strUriYellowKing));
                                        }
                                        else if (pieceType == 1)
                                        {
                                            tempImg.Source = new BitmapImage(new Uri(strUriRedKing));
                                        }

                                   

                                    }
                                }
                                else if (pieceType == 1)// red
                                {
                                    if (endPosition.YPos == GridStartPosition.YPos)
                                    {
                                        //TODO: over here change the image source to king and also update the piece ID 
                                        isKing = true;

                                        if (pieceType == 0)
                                        {
                                            tempImg.Source = new BitmapImage(new Uri(strUriYellowKing));
                                        }
                                        else if (pieceType == 1)
                                        {
                                            tempImg.Source = new BitmapImage(new Uri(strUriRedKing));
                                        }

                                    

                                    }
                                }

                                tempImg.Tag = isKing;
                                sendMoveToServer(GivePanelIndexFromPosition(endPosition), pieceName, validator.getRemovedPieceName(), isKing);


                                tempImg = null;
                                tempParentPanel = null;


                            }
                            else
                            {
                                statusLabel.Content = "Invalid Move";
                            }

                            /*
                             * check for valid moves
                             * 
                             */

                        }
                    }
                    else
                    {
                        statusLabel.Content = "No Piece selected selected";
                    }


                }
                else if (e.Source.GetType() == typeof(Image))
                {
                    Image refImage = (Image)e.Source;


                    int typeOfRefImage = whichTypePiece(refImage.Name);
                

                    if (tempImg != null)
                    {

                        int typeOfEImage = whichTypePiece(tempImg.Name);

                        if (typeOfRefImage == typeOfEImage && typeOfRefImage == PlayerType)
                        {
                            tempImg.Opacity = 1.0;
                            refImage.Opacity = 0.4;
                            statusLabel.Content = "Piece Selected";
                            tempImg = refImage;
                            tempParentPanel = (StackPanel)sender;
                        }
                        else
                        {
                            statusLabel.Content = "You cannot select opposite teams piece";
                        }

                    }
                    else
                    {
                        if (typeOfRefImage == PlayerType)
                        {
                            refImage.Opacity = 0.4;
                            statusLabel.Content = "Piece Selected";
                            tempImg = refImage;
                            tempParentPanel = (StackPanel)sender;
                        }
                        else
                        {
                            statusLabel.Content = "You cannot select opposite teams piece";
                        }
                    
                    }




                }
            }

            catch (Exception exp)
            {
                MessageBox.Show(exp.Message);
            }

        }

        private int GivePanelIndexFromPosition(Position endPosition)
        {
            int pos = (endPosition.XPos - GridStartPosition.XPos) + (endPosition.YPos - GridStartPosition.YPos) * 8;

            return pos;
        }

        private void sendMoveToServer(int finalPanelPosition, string pieceName, string removedPiece, bool isking)
        {
            try{
                DateTime latestTime = DateTime.Now;

                var objMove = new clsGameMoves()
                {
                    FinalPositionPanelId = finalPanelPosition,
                
                    PieceId = pieceName,
                    Player = objGameRoomPlayerViewModel.player,
                    Timestamp = latestTime,
                    GameRoom = objGameRoomPlayerViewModel.gameRoom,
                    ListOfRemovedPieces = removedPiece,
                    IsKing = isking
                };

                lastTimeUpdated = latestTime;

                client_gm.AddMove(objMove);
            }

            catch (Exception exp)
            {
                MessageBox.Show(exp.Message);
            }
        }

        private int whichTypePiece(string pieceName)
        {
            string[] splitStrArr = pieceName.Split('_');

            if (splitStrArr[1] == "0")
            {
                return 0;
            }
            else if (splitStrArr[1] == "1")
            {
                return 1;
            }

            throw new Exception("Invalid Piece Type");

        }

        
        //------------------------checkers Board UI----------------




        private void updateMovesPanel()
        {
            try{
                var gameroomMovesList = client_gm.GetAllMoves(this.objGameRoomPlayerViewModel.gameRoom);
                movesListView.Items.Clear();

                foreach (clsGameMoves moves in gameroomMovesList)
                {

                    Label label = new Label();
                    label.Content = "Move Id: " + moves.MoveId + "    TimeStamp: " + moves.Timestamp + " By Player: " + moves.Player.PlayerName; // playerId replaced by the actual player Name

                    StackPanel panel = new StackPanel();
                    panel.Orientation = Orientation.Horizontal;
                    panel.Children.Add(label);
             
                    movesListView.Items.Add(panel);
                }


                GridStartPosition.XPos = Convert.ToInt32(Math.Floor(FirstStackPanel.PointToScreen(new Point()).X / 60));
                GridStartPosition.YPos = Convert.ToInt32(Math.Floor(FirstStackPanel.PointToScreen(new Point()).Y / 60));

                GridEndPosition.XPos = Convert.ToInt32(Math.Floor(LastStackPanel.PointToScreen(new Point()).X / 60));
                GridEndPosition.YPos = Convert.ToInt32(Math.Floor(LastStackPanel.PointToScreen(new Point()).Y / 60));

                var reversedList = gameroomMovesList.Reverse().ToArray();
                updateGrid(reversedList);
            }

            catch (Exception exp)
            {
                MessageBox.Show(exp.Message);
            }
        }

        private void resetTheUI()
        {
            InitializeComponent();
            BindClickEventsOnPanel();
        }

        private void updateGrid(clsGameMoves[] gameroomMovesList)
        {
            try{
                var latestMoves = new List<clsGameMoves>();

                if(gameroomMovesList.Length == 0)
                {
                    resetTheUI();
                }

                if (this.isFirsTime)
                {
                    foreach (clsGameMoves move in gameroomMovesList)
                    {
                    
                       latestMoves.Add(move);
                    

                    }
                }
                else
                {
                    foreach (clsGameMoves move in gameroomMovesList)
                    {
                        if (move.Timestamp > lastTimeUpdated)
                        {
                            latestMoves.Add(move);
                        }

                    }
                }


                //for enitre board upate on refresh
                isFirsTime = true;

                foreach(clsGameMoves move in latestMoves)
                {
                    string pieceId = move.PieceId;
                    string removedPieceId = move.ListOfRemovedPieces;

                    Grid grid = CheckersGrid;

                
                
                    var panelToTransfer = wherePanel(move.FinalPositionPanelId);

                    //transfer the price from its current to final position and then remove the piece over which it jumps from
                    RemovePieceFromPanelTransfer(pieceId, panelToTransfer, move.IsKing);

                    var peiceToRemove = RemovePieceFromPanel(removedPieceId);
                
               
                }
            }

            catch (Exception exp)
            {
                MessageBox.Show(exp.Message);
            }

        }

        private void RemovePieceFromPanelTransfer(string pieceId, StackPanel panelToTransfer, bool isKing)
        {
            Grid grid = CheckersGrid;
            if (pieceId == "")
            {
                return;
            }
            foreach (UIElement element in grid.Children)
            {
                StackPanel panel = (StackPanel)element;

                if (panel.Children.Count != 0)
                {
                    //get the image element
                    foreach (UIElement innerElement in panel.Children)
                    {
                        if (innerElement.GetType() == typeof(Image))
                        {
                            var img = (Image)innerElement;

                            if (img.Name == pieceId)
                            {
                                if (isKing)
                                {
                                    int PieceType = this.whichTypePiece(img.Name);

                                    img.Tag = isKing;

                                    if(PieceType == 0)
                                    {
                                        img.Source = new BitmapImage(new Uri(strUriYellowKing));
                                    }
                                    else
                                    {
                                        img.Source = new BitmapImage(new Uri(strUriRedKing));
                                    }


                                    
                                }

                                panel.Children.Remove(img);
                                panelToTransfer.Children.Add(img);
                                
                                //make a king if isKing is true
                                

                                return;
                            }


                        }
                    }
                }

            }

            return;
        }

        private Image RemovePieceFromPanel(string pieceId) 
        {
            Grid grid = CheckersGrid;
            if(pieceId == "")
            {
                return null;
            }
           foreach(UIElement element in grid.Children)
            {
                StackPanel panel = (StackPanel)element;

                if(panel.Children.Count != 0)
                {   
                    //get the image element
                    foreach(UIElement innerElement in panel.Children)
                    {
                        if(innerElement.GetType() == typeof(Image))
                        {
                            var img = (Image)innerElement;

                            if(img.Name == pieceId)
                            {
                                panel.Children.Remove(img);

                                return img;
                            }

                                
                        }
                    }
                }

             }

           return null;
        }
        
        private StackPanel wherePanel(int position) 
        {

            int pos = position;
            Grid grid = CheckersGrid;

            return (StackPanel)grid.Children[pos];
        }

        private void updateViewerPanel()
        {
            try{
                var gameroomSubscribersList = client_gm.GetAllViewers(objGameRoomPlayerViewModel.gameRoom);

                viewersListView.Items.Clear();
                foreach (clsGameRoomClient client in gameroomSubscribersList)
                {

                    Label label = new Label();
                    label.Content = "Username: " + client.Player.PlayerUserName + " Type: " + Enum.GetName(typeof(PlayerType), client.PlayerType); // playerId replaced by the actual player Name

                    StackPanel panel = new StackPanel();
                    panel.Orientation = Orientation.Horizontal;
                    panel.Children.Add(label);

                    viewersListView.Items.Add(panel);
                }


                /*
                 Is occupied status of the gameroom
                 */
                isOccupiedBy = gameroomSubscribersList.First().GameRoom.IsOccupiedStatus;
                objGameRoomPlayerViewModel.gameRoom.IsOccupiedStatus = isOccupiedBy;
            }

            catch (Exception exp)
            {
                MessageBox.Show(exp.Message);
            }
        }

        private void updateGridBtn_Click(object sender, RoutedEventArgs e)
        {
            initMyUIElements();
            updateGridBtn.Visibility = Visibility.Hidden;
           
        }

        private void btnReleaseLock_Click(object sender, RoutedEventArgs e)
        {
            objGameRoomPlayerViewModel.gameRoom.IsOccupiedStatus = PlayerType;
            isOccupiedBy = PlayerType;
            client_gm.UpdateGameRoomOccupiedStatus(objGameRoomPlayerViewModel.gameRoom);

            btnReleaseLock.Visibility = Visibility.Hidden;

            //tempImg.Opacity = 1.0;
            //tempImg = null;

        }

        private void UpdateReleaaseButton()
        {
            if(objGameRoomPlayerViewModel.gameRoom.IsOccupiedStatus == PlayerType)
            {
                btnReleaseLock.Visibility = Visibility.Visible;
            }
            else
            {
                btnReleaseLock.Visibility = Visibility.Hidden;
            }
            
        }

        private void Windows_closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            MessageBox.Show("Application will shutdown");
            Application.Current.Shutdown();
            
        }

        //private void button1_Click(object sender, RoutedEventArgs e)
        //{
        //    checkWinEvent();
        //}
    }
}
